/**
 * 虚拟摇杆--方向控制(左侧部分)
 * @author wjc133
 */
class Joystick extends egret.DisplayObjectContainer {
    private outer: egret.Shape = new egret.Shape();
    private inner: egret.Shape = new egret.Shape();

    private outerRadius: number = 50;

    private direction: Direction;
    private speed: number;

    constructor() {
        super();
        this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
    }

    public onAddToStage() {
        this.removeEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);

        this.outer.graphics.lineStyle(2, 0x00ff00);
        this.outer.graphics.beginFill(0xfb6800, 0.7);
        this.outer.graphics.drawCircle(0, 0, this.outerRadius);
        this.outer.graphics.endFill();
        this.addChild(this.outer);

        this.inner.graphics.lineStyle(2, 0x00ff00);
        this.inner.graphics.beginFill(0xff0000, 0.7);
        this.inner.graphics.drawCircle(0, 0, 10);
        this.inner.graphics.endFill();
        this.addChild(this.inner);
    }

    /**
     * 初始定位虚拟摇杆
     * @param x {number} 横坐标
     * @param y {number} 纵坐标
     */
    public locate(x: number, y: number) {
        this.outer.x = x;
        this.outer.y = y;
        this.inner.x = x;
        this.inner.y = y;
    }

    /**
     * 内圈在外圈的范围内移动，内圈的圆心不能超出外圈的范围。
     * 按照 @蛮 提供的算法，可以求得当触摸点是圆外一点时，落在
     * 外圈上的点的坐标。
     * 
     */
    public move(x: number, y: number) {
        let x0 = this.outer.x;
        let y0 = this.outer.y;

        let r1 = Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2));
        // 分发移动事件
        let moveEvent: MoveEvent = new MoveEvent(MoveEvent.MOVE);
        moveEvent.direction = this.calcDirection(Math.asin((x - x0) / r1), y > y0);
        moveEvent.speed = r1 >= this.outerRadius ? 1 : r1 / this.outerRadius;
        if (moveEvent.direction !== this.direction || moveEvent.speed !== this.speed) {
            this.dispatchEvent(moveEvent);
        }
        // 防摇杆溢出
        if (r1 <= this.outerRadius) {
            this.inner.x = x;
            this.inner.y = y;
            return;
        }
        let x2 = (x - x0) / r1 * this.outerRadius + x0;
        let innerMiddleResult = Math.sqrt(Math.pow(this.outerRadius, 2) - Math.pow(x2 - x0, 2));
        let y2 = y > y0 ? innerMiddleResult + y0 : y0 - innerMiddleResult;
        this.inner.x = x2;
        this.inner.y = y2;
    }

    private calcDirection(dig: number, atBottom: boolean = true): Direction {
        let n = Math.PI / 8;
        if (atBottom) {
            if (dig > -n && dig <= n) {
                return Direction.SOUTH;
            } else if (dig > -3 * n && dig <= -n) {
                return Direction.SOUTHWEST;
            } else if (dig > n && dig <= 3 * n) {
                return Direction.SOUTHEAST;
            } else if (dig <= -3 * n) {
                return Direction.WEST;
            } else if (dig > 3 * n) {
                return Direction.EAST;
            }
        } else {
            if (dig > -n && dig <= n) {
                return Direction.NORTH;
            } else if (dig > -3 * n && dig <= -n) {
                return Direction.NORTHWEST;
            } else if (dig > n && dig <= 3 * n) {
                return Direction.NORTHEAST;
            } else if (dig <= -3 * n) {
                return Direction.WEST;
            } else if (dig > 3 * n) {
                return Direction.EAST;
            }
        }
    }
}

